﻿' ----------------------------------------------------------------------------------
' Microsoft Developer & Platform Evangelism
' 
' Copyright (c) Microsoft Corporation. All rights reserved.
' 
' THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
' EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES 
' OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ----------------------------------------------------------------------------------
' The example companies, organizations, products, domain names,
' e-mail addresses, logos, people, places, and events depicted
' herein are fictitious.  No association with any real company,
' organization, product, domain name, email address, logo, person,
' places, or events is intended or should be inferred.
' ----------------------------------------------------------------------------------

Imports Microsoft.Samples.WindowsPhoneCloud.Web.UserAccountWrappers
Imports Microsoft.Samples.WindowsPhoneCloud.Web.Models
Imports Microsoft.Samples.WindowsPhoneCloud.Web.Infrastructure
Imports System.Net
Imports System.Linq.Expressions
Imports System.Data.Services.Common
Imports System.Data.Services
Imports System.Data.Objects
Imports System.Data.Entity.Infrastructure

Namespace Services

    ' Summary:
    '     Sample OData Service exposing SQL Azure data.
    '     This sample service provides read-acess to all the collections of entities of the SQL Azure sample context,
    '     and validates the user credentials
    Public Class SqlAzureSampleODataService
        Inherits DataService(Of ObjectContext)

#If ACS Then
		Private ReadOnly Property UserId() As String
			Get
				Dim identity = TryCast(HttpContext.Current.User.Identity, Microsoft.IdentityModel.Claims.IClaimsIdentity)
				Return identity.Claims.Single(Function(c) c.ClaimType = Microsoft.IdentityModel.Claims.ClaimTypes.NameIdentifier).Value
			End Get
		End Property
#Else
        Private ReadOnly context As HttpContextBase
        Private ReadOnly formsAuth As IFormsAuthentication
        Private ReadOnly membershipService As IMembershipService
        Private ReadOnly userPrivilegesRepository As IUserPrivilegesRepository

        Public Sub New()
            Me.New(New HttpContextWrapper(HttpContext.Current), New SqlDataContext(), New FormsAuthenticationService(), New AccountMembershipService())
        End Sub

        <CLSCompliant(False)> _
        Public Sub New(ByVal context As HttpContextBase, ByVal userPrivilegesRepository As IUserPrivilegesRepository, ByVal formsAuth As IFormsAuthentication, ByVal membershipService As IMembershipService)
            If (context Is Nothing) AndAlso (HttpContext.Current Is Nothing) Then
                Throw New ArgumentNullException("context", "The context cannot be null if not running on a Web context.")
            End If

            Me.context = context
            Me.userPrivilegesRepository = userPrivilegesRepository
            Me.formsAuth = formsAuth
            Me.membershipService = membershipService
        End Sub

        Private ReadOnly Property UserId() As String
            Get
                Dim ticketValue As String = Nothing

                Dim cookie = Me.context.Request.Cookies(Me.formsAuth.FormsCookieName)
                If cookie IsNot Nothing Then
                    ' From cookie.
                    ticketValue = cookie.Value
                ElseIf Me.context.Request.Headers("AuthToken") IsNot Nothing Then
                    ' From HTTP header.
                    ticketValue = Me.context.Request.Headers("AuthToken")
                End If

                If (Not String.IsNullOrEmpty(ticketValue)) Then
                    Dim ticket As FormsAuthenticationTicket

                    Try
                        ticket = Me.formsAuth.Decrypt(ticketValue)
                    Catch
                        Throw New DataServiceException(CInt(Fix(HttpStatusCode.Unauthorized)), "The authorization ticket cannot be decrypted.")
                    End Try

                    If ticket IsNot Nothing Then
                        ' Authorize Sql Azure OData Service usage.
                        Dim auxiliarUserId = Me.membershipService.GetUser(New FormsIdentity(ticket).Name).ProviderUserKey.ToString()
                        If (Not Me.userPrivilegesRepository.HasUserPrivilege(auxiliarUserId, PrivilegeConstants.SqlUsagePrivilege)) Then
                            Throw New DataServiceException(CInt(Fix(HttpStatusCode.Unauthorized)), "You have no permission to use SQL Azure.")
                        End If

                        Return auxiliarUserId
                    Else
                        Throw New DataServiceException(CInt(Fix(HttpStatusCode.Unauthorized)), "The authorization token is no longer valid.")
                    End If
                Else
                    Throw New DataServiceException(CInt(Fix(HttpStatusCode.NotFound)), "Resource not found.")
                End If
            End Get
        End Property
#End If

        Public Shared Sub InitializeService(ByVal config As DataServiceConfiguration)
            config.SetEntitySetAccessRule("SqlSampleData", EntitySetRights.AllRead)
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2
        End Sub

        <QueryInterceptor("SqlSampleData")> _
        Public Function QuerySqlSampleData() As Expression(Of Func(Of SqlSampleData, Boolean))
            Return Function(c) c.IsPublic OrElse c.UserId.Equals(Me.UserId, StringComparison.OrdinalIgnoreCase)
        End Function

        <System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification:="The instance created of the SqlSampleDataContext class is used as the data source of the DataService class.")>
        Protected Overrides Function CreateDataSource() As ObjectContext
            Dim sampleDataContext = TryCast(New SqlDataContext(), IObjectContextAdapter)
            Return sampleDataContext.ObjectContext
        End Function
    End Class
End Namespace